/********************************************************************************
 * Project Name		[JavaEE_JDBC]
 * File Name     	[DynamicProxyDataSource.java]
 * Creation Date 	[2015-01-01]
 * 
 * Copyright© ge.y.yang@gmail.com All Rights Reserved
 * 
 * Work hard, play harder, think big and keep fit
 ********************************************************************************/
package pool.dynamicProxyDataSource;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.Properties;

/**
 * @author 不落的太阳(Sean Yang aka ShortPeace)
 * @version 1.0
 * @since jdk 1.8
 * 
 */
public class DynamicProxyDataSource {

	private static String username; // 数据库访问用户名
	private static String password; // 数据库访问密码
	private static String driverClass; // 数据库驱动类名
	private static String databaseURL; // 数据库访问URL
	private static int initialConnectionNumber = 10; // 连接池中初始化的连接个数
	private static int maxConnectionNumber = 10; // 连接池中最多可以存在的连接个数
	private static int minConnecitonNumber = 10; // 连接池中最少可以存在的连接个数

	int currentConnectionNumber;// 当前连接数

	// 使用LinkedList作为连接池
	private LinkedList<Connection> connectionPool = new LinkedList<Connection>();
	// 使用Connection作为泛型参数比MyConnection作为泛型参数, 符合面向接口编程的原则
	// LinkedList<MyConnection> connectionPool = new LinkedList<MyConnection>();

	static {
		Properties properties = new Properties();
		try {
			properties.load(DynamicProxyDataSource.class.getClassLoader().getResourceAsStream("database.properties"));
			username = properties.getProperty("connection.username");
			password = properties.getProperty("connection.password");
			driverClass = properties.getProperty("connection.driverClass");
			databaseURL = properties.getProperty("connection.url");
			initialConnectionNumber = Integer.parseInt((String) properties.get("connection.initSize"));
			maxConnectionNumber = Integer.parseInt(properties.getProperty("connection.maxSize"));
			minConnecitonNumber = Integer.parseInt(properties.getProperty("connection.minSize"));

			Class.forName(driverClass);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 构造时产生initialConnectionNumber个连接并放入Pool中
	 */
	public DynamicProxyDataSource() {
		for (int i = 0; i < initialConnectionNumber; i++) {
			try {
				this.connectionPool.addLast(this.createConnection());
				this.currentConnectionNumber++;
			} catch (Exception e) {
				throw new ExceptionInInitializerError(e);
			}
		}
	}

	/**
	 * 创建连接
	 * 
	 * @return
	 * @throws SQLException
	 */
	private Connection createConnection() throws SQLException {
		Connection realConnection = DriverManager.getConnection(databaseURL, username, password);
		DynamicProxyConnection proxyHandler = new DynamicProxyConnection(this);
		return proxyHandler.bind(realConnection);
	}

	/**
	 * 释放连接
	 * 
	 * @param connection
	 */
	public void releaseConnection(Connection connection) {
		this.connectionPool.add(connection);
	}

	/**
	 * 获取连接
	 * 
	 * @return
	 * @throws SQLException
	 */
	public Connection getConnection() throws SQLException {
		synchronized (connectionPool) {
			if (connectionPool.size() > 0) {
				return connectionPool.removeFirst();
			}

			if (this.currentConnectionNumber < maxConnectionNumber
					&& this.currentConnectionNumber >= minConnecitonNumber) {
				this.currentConnectionNumber++;
				return this.createConnection();
			}
			throw new SQLException("No connection available");
		}
	}
}
